package com.wangnian.wangcai.util;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wangnian.wangcai.config.Config;

import java.io.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class TaskUtil {

    private static final String fileName = "recording.json";

    // 定义缓存过期时间 - 7天
    private static final long CACHE_EXPIRY_DAYS = 7;
    
    // 修改为ConcurrentHashMap，支持线程安全操作
    public static JSONObject mapCache = new JSONObject();
    
    // 记录每个条目的最后访问时间
    private static Map<String, Long> lastAccessTime = new ConcurrentHashMap<>();
    
    // 最大缓存条目数
    private static final int MAX_CACHE_ENTRIES = 1000;
    
    /**
     * 清理过期缓存
     */
    public static synchronized void cleanupExpiredCache() {
        long currentTime = System.currentTimeMillis();
        long expiryTime = currentTime - TimeUnit.DAYS.toMillis(CACHE_EXPIRY_DAYS);
        
        // 找出过期的键
        List<String> expiredKeys = new ArrayList<>();
        for (Map.Entry<String, Long> entry : lastAccessTime.entrySet()) {
            if (entry.getValue() < expiryTime) {
                expiredKeys.add(entry.getKey());
            }
        }
        
        // 删除过期的缓存
        for (String key : expiredKeys) {
            mapCache.remove(key);
            lastAccessTime.remove(key);
            logger.info("清理过期缓存: {}", key);
        }
        
        // 如果缓存条目过多，也删除最老的条目
        if (mapCache.size() > MAX_CACHE_ENTRIES) {
            // 按最后访问时间排序
            List<String> oldestKeys = lastAccessTime.entrySet().stream()
                    .sorted(Map.Entry.comparingByValue())
                    .limit(mapCache.size() - MAX_CACHE_ENTRIES)
                    .map(Map.Entry::getKey)
                    .collect(Collectors.toList());
            
            for (String key : oldestKeys) {
                mapCache.remove(key);
                lastAccessTime.remove(key);
                logger.info("清理最老缓存: {}", key);
            }
        }
        
        // 保存更新后的缓存
        writeString(JSONObject.toJSONString(mapCache, SerializerFeature.PrettyFormat, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty));
    }
    
    // 添加日志记录器
    private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(TaskUtil.class);

    public static void recording(int level, String code, String name, int type, int count, double price) {
        Recording recording = new Recording();
        recording.setLevel(level);
        recording.setCode(code);
        recording.setDate(DateUtil.getStringToday());
        recording.setType(type);
        recording.setCount(count);
        recording.setPrice(price);
        recording.setName(name);
        TaskUtil.add(recording);
    }

    public static JSONArray getMapCache(String code) {
        // 更新最后访问时间
        lastAccessTime.put(code, System.currentTimeMillis());
        
        JSONArray jsonArray = mapCache.getJSONArray(code);
        return jsonArray == null ? new JSONArray() : jsonArray;
    }

    public static boolean canMai(int level, String code, int type, int count) {
        JSONArray jsonArray = getMapCache(code);
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            if (type == Config.type2) {
                if (jsonObject.getInteger("level") <= level && jsonObject.getString("date").equals(DateUtil.getStringToday()) && jsonObject.getInteger("type") == type) {
                    return false;
                }
            } else {
                if (jsonObject.getInteger("level") == level && jsonObject.getInteger("type") == type && jsonObject.getInteger("count") == count) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 添加任务
     *
     * @param recording
     */
    public synchronized static void add(Recording recording) {
        JSONArray jsonArray = getMapCache(recording.getCode());
        jsonArray.add(recording);
        mapCache.put(recording.getCode(), jsonArray);
        // 更新最后访问时间
        lastAccessTime.put(recording.getCode(), System.currentTimeMillis());
        
        writeString(JSONObject.toJSONString(mapCache, SerializerFeature.PrettyFormat, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty));
        
        // 在添加新条目后检查是否需要清理缓存
        if (mapCache.size() % 50 == 0) {  // 每添加50个条目检查一次
            cleanupExpiredCache();
        }
    }

    public synchronized static void remove(Recording recording) {
        JSONArray jsonArray = getMapCache(recording.getCode());
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            Recording recordingOld = JSONObject.parseObject(jsonObject.toJSONString(), Recording.class);
            if (recordingOld.equals(recording)) {
                jsonArray.remove(i);
                break;
            }
        }
        if (jsonArray.isEmpty()) {
            mapCache.remove(recording.getCode());
            lastAccessTime.remove(recording.getCode());
        } else {
            mapCache.put(recording.getCode(), jsonArray);
            // 更新最后访问时间
            lastAccessTime.put(recording.getCode(), System.currentTimeMillis());
        }
        writeString(JSONObject.toJSONString(mapCache, SerializerFeature.PrettyFormat, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty));
    }

    public synchronized static JSONArray findAll() {
        JSONArray jsonArray = new JSONArray();
        Collection<Object> collection = mapCache.values();
        for (Object object : collection) {
            jsonArray.addAll(JSONArray.parseArray(JSONObject.toJSONString(object)));
        }
        return jsonArray;
    }

    public synchronized static List<Recording> findByCodeAndType(String code, int type) {
        JSONArray jsonArray = getMapCache(code);
        List<Recording> recordings = new ArrayList<>();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            if (jsonObject.getInteger("type") == type) {
                recordings.add(JSONObject.parseObject(jsonObject.toJSONString(), Recording.class));
            }
        }
        return recordings;
    }


    /**
     * 写入文件
     *
     * @param content
     */
    public static void writeString(String content) {
        File file;
        BufferedWriter bufferedWriter = null;
        try {
            file = new File(fileName);
            bufferedWriter = new BufferedWriter(new FileWriter(file));
            bufferedWriter.write(content);
            bufferedWriter.flush();
            bufferedWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                bufferedWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }


    public static String readString() {
        try (FileReader file = new FileReader(fileName);
             BufferedReader bufferedReader = new BufferedReader(file)) {
            StringBuilder content = new StringBuilder();
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                content.append(line);
            }
            return content.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    public static void main(String[] args) {
        mapCache = JSONObject.parseObject(readString());
        System.out.println(mapCache);
//        List<Recording> byCodeAndType = findByCodeAndType("300413", 2);
//        Recording recording = byCodeAndType.get(0);
//        boolean b = canMai(recording.getLevel(), recording.getCode(), recording.getType());
//        System.out.println(b);
//        System.out.println(findAll());
//        System.out.println(JSONObject.toJSONString(byCodeAndType));

    }

    public static class Recording {
        private String name;

        private String code;

        private String date;

        private Double price;

        private int level;

        private int type;

        private int count;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getCount() {
            return count;
        }

        public void setCount(int count) {
            this.count = count;
        }

        public int getType() {
            return type;
        }

        public void setType(int type) {
            this.type = type;
        }

        public int getLevel() {
            return level;
        }

        public void setLevel(int level) {
            this.level = level;
        }

        public String getCode() {
            return code;
        }

        public void setCode(String code) {
            this.code = code;
        }


        public String getDate() {
            return date;
        }

        public void setDate(String date) {
            this.date = date;
        }

        public Double getPrice() {
            return price;
        }

        public void setPrice(Double price) {
            this.price = price;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Recording recording = (Recording) o;
            return level == recording.level && type == recording.type && count == recording.count && Objects.equals(code, recording.code) && Objects.equals(date, recording.date) && Objects.equals(price, recording.price);
        }

        @Override
        public int hashCode() {
            return Objects.hash(code, date, price, level, type, count);
        }
    }
}
